package org.springblade.task.job.report.user;

import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.common.enums.VipServiceEnum;
import org.springblade.common.utils.DateUtils;
import org.springblade.modules.userAnalysis.entity.DailyPayUsersReadPreferenceReport;
import org.springblade.modules.userAnalysis.entity.DailyPayUsersReadSaleReport;
import org.springblade.modules.userAnalysis.entity.DailyPayUsersReport;
import org.springblade.modules.userAnalysis.service.IDailyPayUsersReadPreferenceReportService;
import org.springblade.modules.userAnalysis.service.IDailyPayUsersReadSaleReportService;
import org.springblade.modules.userAnalysis.service.IDailyPayUsersReportService;
import org.springblade.modules.userAnalysis.vo.DailyPayUsersReportVO;
import org.springblade.task.base.param.BaseOrderBookParam;
import org.springblade.task.base.param.BaseParam;
import org.springblade.task.base.param.BaseUserParam;
import org.springblade.task.base.param.BaseUserReadingDataLogParam;
import org.springblade.task.base.service.*;
import org.springblade.task.base.vo.*;
import org.springblade.task.job.base.BaseTaskInfoJob;
import org.springblade.task.quartz.entity.QuartzTask;
import org.springblade.task.quartz.service.IQuartzTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @Title: 付费用户
 * @version V1.0
 */
@Component
public class DailyPayUsersReportJob {

	private static Logger logger = LoggerFactory.getLogger(BaseTaskInfoJob.class);

	@Autowired
	private IQuartzTaskService quartzTaskService;
	// VIP用户数据
	@Autowired
	private IBaseVipUserService baseVipUserService;
	// 虚拟币流水表
	@Autowired
	private IBaseVirtualMoneyFlowLogService baseVirtualMoneyFlowLogService;
	// 电子书订单
	@Autowired
	private IBaseEbookOrderService baseEbookOrderService;
	//网文
	@Autowired
	private IBaseNetChapterOrderService baseNetChapterOrderService;
	// 有声
	@Autowired
	private IBaseAudioChapterOrderService baseAudioChapterOrderService;
	//
	@Autowired
	private IBaseUserService baseUserService;
	// 用户阅读书籍数据
	@Autowired
	private IBaseUserReadingDataLogService baseUserReadingDataLogService;
	// 书籍基本信息
	@Autowired
	private IBaseEbookInfoService baseEbookInfoService;
	// 每日付费用户画像
	@Autowired
	private IDailyPayUsersReportService dailyPayUsersReportService;
	// 付费用户阅读偏好
	@Autowired
	private IDailyPayUsersReadPreferenceReportService dailyPayUsersReadPreferenceReportService;
	// 付费用户消费类型比
	@Autowired
	private IDailyPayUsersReadSaleReportService dailyPayUsersReadSaleReportService;

	/**
	 * 1、简单任务示例（Bean模式）
	 */
	@XxlJob("DailyPayUsersReportJob")
	public ReturnT<String> DailyPayUsersReportJob(String param) throws Exception {
		System.out.println(DateUtils.currentDateTime() + " -- XXL-JOB, Hello World.");
		System.err.println("执行静态定时任务日期: " + DailyPayUsersReportJob.class.getSimpleName());
		QuartzTask quartzTask = quartzTaskService.queryByTaskName(DailyPayUsersReportJob.class.getSimpleName(), -7);
		// 今日
		String todayDate = DateUtils.crutDate();
		String taskDate = quartzTask.getTaskDate();
		while (taskDate.compareTo(todayDate) < 0) {
			// 当时间大于5点，跳出执行
//			if (DateUtils.getHour24() > 5) {
//				break;
//			}
			// 再加一个凌晨1点判断
			currMethod(taskDate);
			// 增加1天
			taskDate = DateUtils.dateAddDay(taskDate, 1);
		}
		quartzTask.setTaskDate(taskDate);
		quartzTaskService.saveQuartzTask(quartzTask);
		return ReturnT.SUCCESS;
	}

	/**
	 *
	 * @param taskDate
	 */
	public void currMethod(String taskDate) {

		String startTime = DateUtils.getDateStartTime(taskDate);
		String endTime = DateUtils.getDayEndTime(taskDate);
		// 今日全部付费用户
		Set<String> allPinSet = new HashSet<>();
		Set<String> newPinSet = new HashSet<>();
		Set<String> oldPinSet = new HashSet<>();

		// vip用户：今日在vip区间内的用户数据
		BaseUserParam userParam = new BaseUserParam();
		userParam.setStartDate(startTime);
		userParam.setEndDate(endTime);
		List<BaseVipUserVO> vipUserVOList = baseVipUserService.queryVipUserList(userParam);
		List<DailyPayUsersReport> payUsersReportList = new ArrayList<>();
		DailyPayUsersReport payUsersReport = null;
		for (BaseVipUserVO vipUserVO : vipUserVOList) {
			// 获取用户
			String pin = vipUserVO.getPin();
			allPinSet.add(pin);
			// vip创建日期
			String created = DateUtils.crutDate(vipUserVO.getCreated());

			payUsersReport = new DailyPayUsersReportVO();
			payUsersReport.setDate(taskDate);
			payUsersReport.setPin(vipUserVO.getPin());
			payUsersReport.setBusinessType(1);
			if(taskDate.equals(created)) {
				payUsersReport.setJudgeVip(2); // 新VIP
				newPinSet.add(pin);
			} else {
				payUsersReport.setJudgeVip(1);
				oldPinSet.add(pin);
			}

			if (VipServiceEnum.SERVICE_TYPE_MONTH.getType() == vipUserVO.getServiceType()) {
				payUsersReport.setAmount(VipServiceEnum.SERVICE_TYPE_MONTH.getValue());
			} else if (VipServiceEnum.SERVICE_TYPE_SEASON_CARD.getType() == vipUserVO.getServiceType()) {
				payUsersReport.setAmount(VipServiceEnum.SERVICE_TYPE_SEASON_CARD.getValue());
			} else if (VipServiceEnum.SERVICE_TYPE_YEAR.getType() == vipUserVO.getServiceType()) {
				payUsersReport.setAmount(VipServiceEnum.SERVICE_TYPE_YEAR.getValue());
			} else if (VipServiceEnum.SERVICE_TYPE_DAY.getType() == vipUserVO.getServiceType()) {
				payUsersReport.setAmount(VipServiceEnum.SERVICE_TYPE_DAY.getValue());
			} else if (VipServiceEnum.SERVICE_TYPE_MONTHLY_PACKAGE.getType() == vipUserVO.getServiceType()) {
				payUsersReport.setAmount(VipServiceEnum.SERVICE_TYPE_MONTHLY_PACKAGE.getValue());
			}
			payUsersReport.setOrdersNum(1);
			payUsersReport.setCreated(new Date());
			payUsersReportList.add(payUsersReport);
		}

		// 虚拟币流水表 : 充值
		BaseParam baseParam = new BaseParam();
		baseParam.setStartDate(startTime);
		baseParam.setEndDate(endTime);
		List<BaseVirtualMoneyFlowLogVO> virtualMoneyFlowLogVOList = baseVirtualMoneyFlowLogService.queryVirtualMoneyFlowLogList(baseParam);
		for (BaseVirtualMoneyFlowLogVO virtualMoneyFlowLogVO : virtualMoneyFlowLogVOList) {
			// 获取用户
			String pin = virtualMoneyFlowLogVO.getPin();
			allPinSet.add(pin);
			payUsersReport = new DailyPayUsersReportVO();
			payUsersReport.setDate(taskDate);
			payUsersReport.setPin(virtualMoneyFlowLogVO.getPin());
			payUsersReport.setBusinessType(2);

			if(newPinSet.contains(pin)) {
				payUsersReport.setJudgeVip(2); // 新VIP
			} else if(oldPinSet.contains(pin)){
				payUsersReport.setJudgeVip(1);
			}

			payUsersReport.setAmount(virtualMoneyFlowLogVO.getAmount());
			payUsersReport.setOrdersNum(1);
			payUsersReport.setCreated(new Date());
			payUsersReportList.add(payUsersReport);
		}

		// 用户订单数据
		BaseOrderBookParam param = new BaseOrderBookParam();
		param.setStartDate(startTime);
		param.setEndDate(endTime);
		// 电子书订单付费用户
		List<BaseEbookOrderVO> ebookOrderPinList = baseEbookOrderService.queryPayUserList(param);
		// 网文订单付费用户
		List<BaseEbookOrderVO> netChapterOrderPinList = baseNetChapterOrderService.queryPayUserList(param);
		// 有声订单付费用户
		List<BaseEbookOrderVO> audioChapterOrderPinList = baseAudioChapterOrderService.queryPayUserList(param);

		// 查询书籍对应的书籍类型
		List<BaseEbookInfoVO> ebookInfoVOList = baseEbookInfoService.queryEbookAndTypeNameList();
		Map<Long, String> ebookTypeNameMap = new HashMap<>();
		for (BaseEbookInfoVO ebookInfoVO : ebookInfoVOList) {
			ebookTypeNameMap.put(ebookInfoVO.getEbookId(), ebookInfoVO.getTypeName());
		}

		// 书籍消费类型对应销量
		Map<String, Integer> ebookTypeSaleMap = new HashMap<>();
		// 用户电子书、网文、有声订单
		orderComm(taskDate, ebookOrderPinList, ebookTypeNameMap, ebookTypeSaleMap, payUsersReportList, allPinSet, newPinSet, oldPinSet, 3);
		orderComm(taskDate, netChapterOrderPinList, ebookTypeNameMap, ebookTypeSaleMap, payUsersReportList,allPinSet, newPinSet, oldPinSet, 4);
		orderComm(taskDate, audioChapterOrderPinList, ebookTypeNameMap, ebookTypeSaleMap, payUsersReportList,allPinSet, newPinSet, oldPinSet, 5);

		// 查询今日用户阅读数据
		BaseUserReadingDataLogParam readingDataLogParam = new BaseUserReadingDataLogParam();
		readingDataLogParam.setStartDate(DateUtils.getDateStartTime(taskDate));
		readingDataLogParam.setEndDate(DateUtils.getDayEndTime(taskDate));
		List<BaseUserReadingDataLogVO> readingDataLogVOList = baseUserReadingDataLogService.queryTodayReadBookList(readingDataLogParam);
		// 用户对应阅读信息
		Map<String, BaseUserReadingDataLogVO> userReadingDataLogVOMap = new HashMap<>();
		// 阅读类型偏好
		Map<String, Integer> readTypePreferenceMap = new HashMap<>();
		// 用户阅读数据
		for (BaseUserReadingDataLogVO readingDataLogVO : readingDataLogVOList) {
			// 如果在付费用户列表内
			if (allPinSet.contains(readingDataLogVO.getPin())) {
				userReadingDataLogVOMap.put(readingDataLogVO.getPin(), readingDataLogVO);
				// 阅读类型偏好阅读量
				String typeName = ebookTypeNameMap.get(readingDataLogVO.getBookId());
				int num = readTypePreferenceMap.get(typeName) == null ? 0 : readTypePreferenceMap.get(typeName);
				readTypePreferenceMap.put(typeName, num + 1);
			}
		}

		// 今日之前的全部用户 TODO
		userParam.setToday(endTime);
		List<BaseUserVO> userVOList = baseUserService.queryUserList(userParam);
		Map<String, BaseUserVO> userVOMap = new HashMap<>();
		for(BaseUserVO userVO :  userVOList) {
			userVOMap.put(userVO.getPin(), userVO);
		}
		// 遍历今日付费用户
		for (DailyPayUsersReport dailyPayUsersReport: payUsersReportList) {
			String pin = dailyPayUsersReport.getPin();
			BaseUserVO userVO  = userVOMap.get(pin);
			if(null == userVO) {
				continue;
			}
			if (userVO.getFirstLoginTime().substring(0, 10).equals(taskDate)) {
				dailyPayUsersReport.setUserType(1);
			} else {
				dailyPayUsersReport.setUserType(2);
			}
			dailyPayUsersReport.setGender(userVO.getGender());
			dailyPayUsersReport.setPin(userVO.getPin());
			dailyPayUsersReport.setCity(userVO.getCity());
			dailyPayUsersReport.setProvince(userVO.getProvince());
			dailyPayUsersReport.setDistrict(userVO.getDistrict());
			dailyPayUsersReport.setDate(taskDate);
			if (!StringUtils.isEmpty(userVO.getBirthday())) {
				int age = DateUtils.getYear(new Date()) - Integer.parseInt(userVO.getBirthday());
				if (age < 18) {
					dailyPayUsersReport.setAge("18岁以下");
				} else if (age >= 18 && age <= 24) {
					dailyPayUsersReport.setAge("18-24岁");
				} else if (age >= 25 && age <= 30) {
					dailyPayUsersReport.setAge("25-30岁");
				} else if (age >= 31 && age <= 34) {
					dailyPayUsersReport.setAge("31-34岁");
				} else if (age >= 35) {
					dailyPayUsersReport.setAge("35岁及以上");
				}
			}

			// 阅读时长
			BaseUserReadingDataLogVO readingDataLogVO = userReadingDataLogVOMap.get(pin);
			if (null != readingDataLogVO) {
				int length = readingDataLogVO.getLength();
				dailyPayUsersReport.setLength(length);
				int m = length / 60;
				if (m > 0 && m < 10) {
					dailyPayUsersReport.setTimeInterval("0-10");
				} else if (m >= 10 && m < 20) {
					dailyPayUsersReport.setTimeInterval("10-20");
				} else if (m >= 20 && m < 30) {
					dailyPayUsersReport.setTimeInterval("20-30");
				} else if (m >= 30 && m < 40) {
					dailyPayUsersReport.setTimeInterval("30-40");
				} else if (m >= 40 && m < 50) {
					dailyPayUsersReport.setTimeInterval("40-50");
				} else if (m >= 50 && m < 60) {
					dailyPayUsersReport.setTimeInterval("50-60");
				} else if (m >= 60) {
					dailyPayUsersReport.setTimeInterval("60以上");
				}
				// 阅读时间段
				String readTime = readingDataLogVO.getStartTime().substring(12, 17);
				dailyPayUsersReport.setReadTime(readTime);
			}
		}
		dailyPayUsersReportService.saveBatch(payUsersReportList);


		// 阅读偏好分布
		List<DailyPayUsersReadPreferenceReport> readPreferenceReportList = new ArrayList<>();
		DailyPayUsersReadPreferenceReport usersReadPreferenceReport = null;
		Iterator itPreference = readTypePreferenceMap.keySet().iterator();
		while (itPreference.hasNext()) {
			String key = itPreference.next().toString();
			usersReadPreferenceReport = new DailyPayUsersReadPreferenceReport();
			usersReadPreferenceReport.setDate(taskDate);
			usersReadPreferenceReport.setReadPreference(key);
			usersReadPreferenceReport.setNum(readTypePreferenceMap.get(key));
			readPreferenceReportList.add(usersReadPreferenceReport);
		}
		dailyPayUsersReadPreferenceReportService.saveBatch(readPreferenceReportList);


		// 消费分类占比
		List<DailyPayUsersReadSaleReport> readSaleReportList = new ArrayList<>();
		DailyPayUsersReadSaleReport readSaleReport = null;
		Iterator itSale = ebookTypeSaleMap.keySet().iterator();
		while (itSale.hasNext()) {
			String key = itSale.next().toString();
			readSaleReport = new DailyPayUsersReadSaleReport();
			readSaleReport.setDate(taskDate);
			readSaleReport.setSaleType(key);
			readSaleReport.setNum(readTypePreferenceMap.get(key));
			readSaleReportList.add(readSaleReport);
		}
		dailyPayUsersReadSaleReportService.saveBatch(readSaleReportList);

	}

	/**
	 * 订单
	 * @param taskDate 日期
	 * @param orderPinList 用户订单列表
	 * @param ebookTypeNameMap 书籍对应类型
	 * @param ebookTypeSaleMap   书籍消费类型对应销量
	 * @param businessType  业务类型： 1:VIP, 2:充值, 3:电子书, 4:网文, 5:有声
	 * @param allPinSet  付费用户
	 */
	private void orderComm(String taskDate, List<BaseEbookOrderVO> orderPinList, Map<Long, String> ebookTypeNameMap,
						    Map<String, Integer> ebookTypeSaleMap, List<DailyPayUsersReport> payUsersReportList,
						   Set<String> allPinSet, Set<String> newPinSet, Set<String> oldPinSet, int businessType) {
		for (BaseEbookOrderVO ebookOrderVO : orderPinList) {
			// 获取用户
			String pin = ebookOrderVO.getPin();
			allPinSet.add(pin);
			DailyPayUsersReportVO payUsersReport = new DailyPayUsersReportVO();
			payUsersReport.setDate(taskDate);
			payUsersReport.setPin(ebookOrderVO.getPin());
			payUsersReport.setBusinessType(businessType);
			if(newPinSet.contains(pin)) {
				payUsersReport.setJudgeVip(2); // 新VIP
			} else if(oldPinSet.contains(pin)){
				payUsersReport.setJudgeVip(1);
			}
			payUsersReport.setAmount(ebookOrderVO.getPayAmount());
			payUsersReport.setOrdersNum(ebookOrderVO.getOrderNum());
			payUsersReport.setCreated(new Date());
			payUsersReportList.add(payUsersReport);
			// 书籍类型对应销量
			String typeName = ebookTypeNameMap.get(ebookOrderVO.getEbookId());
			int num = ebookTypeSaleMap.get(typeName) == null ? 0 : ebookTypeSaleMap.get(typeName);
			ebookTypeSaleMap.put(typeName, num + 1);
		}
	}


	public void init() {
		logger.info("init");
	}

	public void destroy() {
		logger.info("destory");
	}
}
